package com.rtsapp.server.profiling;


import java.util.concurrent.atomic.AtomicLong;

/**
 * 周期性的,累积型的统计类
 *  比如统计每秒网络流量, 每小时流量适合这个
 */
public class  PeriodSummationProfilling{

    //一个累计周期
    private final PeriodClock clock;
    //用于记录
    private final ExecuteProfilling profilling;

    //总的数量
    private final AtomicLong total = new AtomicLong(0);

    //最近的一个周期的累计数量
    private volatile long lastPeriodAmount = 0;

    //当前的时间
    private final AtomicLong atomicCurTimeMills = new AtomicLong(0);
    private volatile long curTimeMills = 0;


    public PeriodSummationProfilling(PeriodClock clock, ExecuteProfilling profilling) {
        this.clock = clock;
        this.profilling = profilling;
    }

    /**
     * 累计输入
     * @param delta
     */
    public void sum( long delta ){

        // 1. 累计输入的字节
        long totalAmount = total.addAndGet( delta );

        // 2. 如果秒钟的时间，大于最后记录的时间，认为已经过了1秒, 记录这一秒的流量
        long watchTime = clock.getTimeMills();
        if( watchTime > curTimeMills){

            // 如果时间相等于上一次的秒数, 则重置成当前秒数（ 这是原子操作，）， 然后当前时间设置为当前时间
            // 这里并不是绝对线程安全，但是由于时间是秒钟，代码执行所需时间又几乎在纳秒级，可以认为它在99.99999%的情况下是线程安全的，如果出现意外，结果也仅仅是统计不够准确, 不会有奔溃问题， 可以接受
            if( atomicCurTimeMills.compareAndSet(curTimeMills, watchTime  ) ){
                curTimeMills = watchTime;
                total.addAndGet(-totalAmount);
                profilling.logSuccess( totalAmount );

                //设置为最后一个周期的数量
                lastPeriodAmount = totalAmount;
            }
        }
    }

    /**
     * 取得最近一个周期的累计数量
     * @return
     */
    public long getLastPeriodAmount() {
        long watchTime = clock.getTimeMills();
        //如果最近1秒内没有任何吞吐量，吞吐量为0
        if( watchTime - curTimeMills > 1L ){
            return 0;
        }else {
            return lastPeriodAmount;
        }
    }
}